import asyncio
import logging
import time
from typing import Dict, Any, Callable
from datetime import datetime
from .error_types import ErrorContext
from .error_classifier import ErrorClassifier
from .retry_engine import RetryDecisionEngine, CircuitBreaker

logger = logging.getLogger(__name__)


class RobustExecutor:
    """健壮执行器 - 集成错误处理、重试和断路器"""
    
    def __init__(self):
        self.circuit_breakers = {}  # 服务级别的断路器
        self.error_stats = {}  # 错误统计
    
    async def execute_with_retry(
        self, 
        func: Callable, 
        service_name: str,
        *args, 
        **kwargs
    ) -> Any:
        """执行函数并处理错误重试"""
        
        error_context = None
        
        # 获取或创建断路器
        if service_name not in self.circuit_breakers:
            self.circuit_breakers[service_name] = CircuitBreaker()
        
        circuit_breaker = self.circuit_breakers[service_name]
        
        while True:
            try:
                # 通过断路器执行
                if asyncio.iscoroutinefunction(func):
                    result = await circuit_breaker.call(func, *args, **kwargs)
                else:
                    result = circuit_breaker.call(func, *args, **kwargs)
                
                # 成功执行，记录统计
                self._record_success(service_name)
                
                return result
                
            except Exception as e:
                # 分类错误
                error_type = ErrorClassifier.classify_error(e)
                
                # 创建或更新错误上下文
                if error_context is None:
                    error_context = ErrorContext(
                        error_type=error_type,
                        original_exception=e,
                        additional_info={"service": service_name}
                    )
                else:
                    error_context.attempt_number += 1
                    error_context.last_attempt_time = datetime.now()
                
                # 记录错误统计
                self._record_error(service_name, error_type, e)
                
                # 判断是否应该重试
                if not RetryDecisionEngine.should_retry(error_context):
                    logger.error(f"Max retries reached for {service_name}: {str(e)}")
                    raise e
                
                # 计算延迟并等待
                delay = RetryDecisionEngine.calculate_delay(error_context)
                if delay > 0:
                    logger.warning(f"Retrying {service_name} in {delay:.2f}s (attempt {error_context.attempt_number})")
                    await asyncio.sleep(delay)
    
    def _record_success(self, service_name: str):
        """记录成功统计"""
        if service_name not in self.error_stats:
            self.error_stats[service_name] = {
                "total_calls": 0,
                "success_calls": 0,
                "error_calls": 0,
                "last_success": None,
                "error_types": {}
            }
        
        stats = self.error_stats[service_name]
        stats["total_calls"] += 1
        stats["success_calls"] += 1
        stats["last_success"] = datetime.now()
    
    def _record_error(self, service_name: str, error_type, exception: Exception):
        """记录错误统计"""
        if service_name not in self.error_stats:
            self.error_stats[service_name] = {
                "total_calls": 0,
                "success_calls": 0,
                "error_calls": 0,
                "last_error": None,
                "error_types": {}
            }
        
        stats = self.error_stats[service_name]
        stats["total_calls"] += 1
        stats["error_calls"] += 1
        stats["last_error"] = datetime.now()
        
        # 错误类型统计
        error_type_str = str(error_type)
        if error_type_str not in stats["error_types"]:
            stats["error_types"][error_type_str] = {
                "count": 0,
                "last_occurrence": None,
                "sample_message": str(exception)
            }
        
        stats["error_types"][error_type_str]["count"] += 1
        stats["error_types"][error_type_str]["last_occurrence"] = datetime.now()
    
    def get_service_health(self, service_name: str) -> Dict[str, Any]:
        """获取服务健康状态"""
        if service_name not in self.error_stats:
            return {
                "status": "unknown",
                "success_rate": 0,
                "circuit_breaker_state": "CLOSED",
                "total_calls": 0
            }
        
        stats = self.error_stats[service_name]
        success_rate = stats["success_calls"] / max(stats["total_calls"], 1)
        
        circuit_breaker_state = "CLOSED"
        if service_name in self.circuit_breakers:
            circuit_breaker_state = self.circuit_breakers[service_name].get_state()
        
        # 判断健康状态
        if circuit_breaker_state == "OPEN":
            status = "unhealthy"
        elif success_rate >= 0.95:
            status = "healthy"
        elif success_rate >= 0.8:
            status = "degraded"
        else:
            status = "unhealthy"
        
        return {
            "status": status,
            "success_rate": success_rate,
            "circuit_breaker_state": circuit_breaker_state,
            "total_calls": stats["total_calls"],
            "success_calls": stats["success_calls"],
            "error_calls": stats["error_calls"],
            "last_success": stats.get("last_success"),
            "last_error": stats.get("last_error"),
            "error_breakdown": stats.get("error_types", {})
        }
    
    def get_all_service_health(self) -> Dict[str, Dict[str, Any]]:
        """获取所有服务的健康状态"""
        health_status = {}
        
        # 获取已知服务状态
        for service_name in self.error_stats.keys():
            health_status[service_name] = self.get_service_health(service_name)
        
        # 添加只有断路器没有统计的服务
        for service_name in self.circuit_breakers.keys():
            if service_name not in health_status:
                health_status[service_name] = self.get_service_health(service_name)
        
        return health_status
    
    def reset_service_circuit_breaker(self, service_name: str):
        """重置服务断路器"""
        if service_name in self.circuit_breakers:
            self.circuit_breakers[service_name].reset()
            logger.info(f"Reset circuit breaker for {service_name}")
    
    def clear_service_stats(self, service_name: str):
        """清除服务统计"""
        if service_name in self.error_stats:
            del self.error_stats[service_name]
            logger.info(f"Cleared stats for {service_name}")


# 全局执行器实例
robust_executor = RobustExecutor()


# 装饰器形式的便捷接口
def with_retry(service_name: str):
    """重试装饰器"""
    def decorator(func):
        async def wrapper(*args, **kwargs):
            return await robust_executor.execute_with_retry(func, service_name, *args, **kwargs)
        return wrapper
    return decorator